#include "../Base/StdAfx.h"
#include "DebugRender.h"
#include "PhysX.h"
#include "../Base/DXDevice.h"
#include "../Base/GameEngine.h"

#include "../Base/vertex.h"

#pragma comment(lib, "PhysXLoader.lib")

DebugRender::DebugRender(): m_pVertexDeclaration(0), m_Effect(0),
m_pVertexBufferLine(0),m_pVertexBufferPoint(0), m_LineData(0), m_PointData(0),
m_NumVertices(0),m_NumIndices(0), m_Lines(0), m_Points(0)
{
	Init();
}

void DebugRender::LoadShader()
{
	ID3D10Blob* ErrorsPtr;

	DWORD ShaderFlags = D3D10_SHADER_ENABLE_STRICTNESS;
	#if defined(_DEBUG) || defined(DEBUG)
		ShaderFlags |= D3D10_SHADER_DEBUG;
	#endif
	D3DX10CreateEffectFromFile(_T("./shaders/PosCol.fx"), NULL, NULL, "fx_4_0", 
		ShaderFlags, NULL, DXDEVICE->GetDevice(),  NULL, NULL, &m_Effect, &ErrorsPtr, NULL);
	if(ErrorsPtr)
	{
		char* errors = (char*)ErrorsPtr->GetBufferPointer();
		OutputDebugStringA(errors);
		PostQuitMessage(0);
	}else{
		m_Tech = m_Effect->GetTechniqueByName("Render");
		m_WVPVar = m_Effect->GetVariableBySemantic("WorldViewProjection")->AsMatrix();
	}
}

DebugRender::~DebugRender(void)
{
	Cleanup();
}
void DebugRender::Init()
{
	//default material color is white
	LoadShader();

	BuildVertexDeclaration();

	if(m_Lines != 0)
		BuildVertexBufferLines();
	if(m_Points != 0)
		BuildVertexBufferPoints();

	BuildIndexBuffer();
}
void DebugRender::BuildVertexDeclaration()
{
	const D3D10_INPUT_ELEMENT_DESC layoutScene[] =
	{
		{ "POSITION",  0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
		{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
	};
	UINT numElementsScene = sizeof(layoutScene)/sizeof(layoutScene[0]);
	D3D10_PASS_DESC passDesc;
	m_Tech->GetPassByIndex(0)->GetDesc(&passDesc);
	HR(DXDEVICE->GetDevice()->CreateInputLayout(layoutScene, numElementsScene, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize,  &m_pVertexDeclaration));
}
void DebugRender::BuildVertexBufferPoints()
{
	vector<VertexPC> v;
	v.reserve(m_Points);

	for(NxU32 t = 0; t < m_Points; ++t)
	{
		v.push_back(VertexPC((float)m_PointData->p.x, (float)m_PointData->p.y, (float)m_PointData->p.z, MakeColor(m_PointData->color)));
		++m_PointData;
	}

	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( VertexPC ) * m_Points;
	bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = &v[0];
	HR(DXDevice::GetSingleton()->GetDevice()->CreateBuffer( &bd, &InitData, &m_pVertexBufferPoint ));


}
void DebugRender::BuildVertexBufferLines()
{
	// Now lock it to obtain a pointer to its internal data, and write the
	// cube's vertex data.

	vector<VertexPC> v;
	v.reserve(m_Lines * 2);

	for(NxU32 t = 0; t < m_Lines; ++t)
	{
		v.push_back(VertexPC((float)m_LineData->p0.x, (float)m_LineData->p0.y, (float)m_LineData->p0.z, D3DXVECTOR4(1,1,1,1))); // MakeColor(m_LineData->color)));
		v.push_back(VertexPC((float)m_LineData->p1.x, (float)m_LineData->p1.y, (float)m_LineData->p1.z, D3DXVECTOR4(1,1,1,1))); // MakeColor(m_LineData->color)));
		++m_LineData;
	}

	D3D10_BUFFER_DESC bd;
	bd.Usage = D3D10_USAGE_DEFAULT;
	bd.ByteWidth = sizeof( VertexPC ) * m_Lines*2;
	bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
	bd.CPUAccessFlags = 0;
	bd.MiscFlags = 0;
	D3D10_SUBRESOURCE_DATA InitData;
	InitData.pSysMem = &v[0];
	HR(DXDevice::GetSingleton()->GetDevice()->CreateBuffer( &bd, &InitData, &m_pVertexBufferLine ));


}
void DebugRender::BuildIndexBuffer()
{
}

void DebugRender::Cleanup()
{
	if(m_Effect) m_Effect->Release();
	if(m_pVertexBufferLine) m_pVertexBufferLine->Release();
	if(m_pVertexBufferPoint) m_pVertexBufferPoint->Release();
	if(m_pVertexDeclaration) m_pVertexDeclaration->Release();
}
void DebugRender::Draw()
{
	DXDEVICE->GetMatrixen(m_View, m_Proj);
	DXDEVICE->GetDevice()->IASetInputLayout(m_pVertexDeclaration);

	m_WVPVar->SetMatrix((float*)&(m_World*m_View*m_Proj));

	UINT stride = sizeof(VertexPC);
	UINT offset = 0;

	if(m_Points != 0)
	{
		DXDevice::GetSingleton()->GetDevice()->IASetVertexBuffers(0, 1, &m_pVertexBufferPoint, &stride, &offset);
		DXDevice::GetSingleton()->GetDevice()->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_POINTLIST);

		D3D10_TECHNIQUE_DESC tech;
		m_Tech->GetDesc( &tech);
		for(UINT t = 0; t < tech.Passes; ++t)
		{
			m_Tech->GetPassByIndex(t)->Apply(0);
			DXDEVICE->GetDevice()->Draw(m_Points,0);
		}
	}

	stride = sizeof(VertexPC);
	offset = 0;

	if(m_Lines != 0)
	{
		DXDevice::GetSingleton()->GetDevice()->IASetVertexBuffers(0, 1, &m_pVertexBufferLine, &stride, &offset);
		DXDevice::GetSingleton()->GetDevice()->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_LINELIST);

		D3D10_TECHNIQUE_DESC tech;
		m_Tech->GetDesc( &tech);
		for(UINT t = 0; t < tech.Passes; ++t)
		{
			m_Tech->GetPassByIndex(t)->Apply(0);
			DXDEVICE->GetDevice()->Draw(m_Lines*2,0);
		}
	}
}

void DebugRender::RenderData(const NxDebugRenderable *data)
{
	m_Points = data->getNbPoints();
	m_Lines = data->getNbLines();
	m_LineData = data->getLines();
	m_PointData = data->getPoints();

	Cleanup();
	Init();
}

D3DXVECTOR4 DebugRender::MakeColor(NxU32 col)
{
	NxF32 Blue = NxF32((col)&0xff)/255.0f;
	NxF32 Green = NxF32((col>>8)&0xff)/255.0f;
	NxF32 Red = NxF32((col>>16)&0xff)/255.0f;
	return D3DXVECTOR4((float)Red, (float)Green, (float)Blue, 1);
}
